#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
import os
import random
import time
from multiprocessing import Process, JoinableQueue


def product(q):
    for i in range(2):
        time.sleep(random.randint(1, 3))
        print("\033[45m{} 生产了 包子 {}\033[0m".format(os.getpid(), i))
        q.put(i)


def consume(q):
    while True:
        time.sleep(random.randint(1, 3))
        res = q.get()
        if res is None: break
        print("{} 吃掉了 包子 {}".format(os.getpid(), res))
        q.task_done()       # 1、当取走代码时,通知队列取走了一次


if __name__ == '__main__':
    q = JoinableQueue()
    p1 = Process(target=product, args=(q,))
    p2 = Process(target=product, args=(q,))
    p3 = Process(target=product, args=(q,))
    c1 = Process(target=consume, args=(q,))
    c2 = Process(target=consume, args=(q,))
    c1.daemon = True        # 守护进程需要运行在主进程之前，守护进程会在主进程代码执行结束后就终止
    c2.daemon = True

    p1.start()
    p2.start()
    p3.start()
    c1.start()
    c2.start()

    p1.join()       # 等待子进程运行完之后在执行主进程
    p2.join()
    p3.join()

    q.join()        # # 等待队列被取干净， 结束意味着主进程的代码运行完毕 -->
                        # 生产运行完毕并且队列中的数据也被取干净了-->
                        # 消费者也就没有意义了
    print("master")

""" 
    # JoinableQueue()Queue对象，但队列允许项目的使用者通知生成者项目已经被成功处理。通知进程是使用共享的信号和条件变量来实现
    1、开启子进程     Process(target=product, args=(q,)) # 传递q
    2、启动子进程     p1.start()  生产者 开始生产
    3、启动子进程     c1.start()  消费者 开始消费
        3.1、  消费者q.task_done()       # 当取走代码时,通知队列取走了一次
        3.2、  q.join()  等待队列被取干净
    4、待子进程运行完， 每个进程都需要join, 否则p1结束时会直接到 master进程
    5、当子进程都运行完了，打印master, 子进程 设置为了 daemon=True
    6、当父进程都结束了，子进程也会跟着一并结束
"""